﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

#define USE_WCF_METASERVICE_CLIENT

using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;

namespace Galaktika.BI.Silverlight.Services
{
    using Galaktika.BI.Silverlight.Services.MetaService;
    using Galaktika.BI.Extensibility.Dom;
    using Galaktika.BI.Runtime.Services;
    using System.Text;
    using System.IO;

    public class SyncMetaService : IDisposable
    {
#if USE_WCF_METASERVICE_CLIENT
        MetaServiceSoapClient m_Client;
#else
        WebRequest m_Client;
#endif
        private ManualResetEvent m_Event = new ManualResetEvent(false);
        IEnumerable<AppItemDescriptor> m_Res;

        public SyncMetaService()
        {
#if USE_WCF_METASERVICE_CLIENT
            m_Client = Galaktika.BI.Runtime.Services.ServiceManagerHelper.CreateService<MetaServiceSoapClient, MetaServiceSoap>();
            m_Client.GetAppItemsCompleted += new EventHandler<GetAppItemsCompletedEventArgs>(Client_GetVariablesCompleted);
            m_Client.SetAppItemCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(Client_SetVariablesCompleted);
#else
            //var client = Galaktika.BI.Runtime.Services.ServiceManager.CreateService<MetaServiceSoapClient, MetaServiceSoap>();
            //m_Client = WebRequest.Create(client.Endpoint.Address.Uri);
            m_Client = WebRequest.Create(new Uri(new Uri(ServiceManager.BaseAddress), "MetaServiceHandler.asmx"));
            m_Client.Method = "POST";
            m_Client.ContentType = "application/x-www-form-urlencoded";
#endif
        }

        void Client_SetVariablesCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                this.Error = e.Error;
            }
            m_Event.Set();
        }

        void Client_GetVariablesCompleted(object sender, GetAppItemsCompletedEventArgs e)
        {
            this.OnGetUserSettingsAsyncCompleted(e);

            if (e.Error == null)
            {
                m_Res = e.Result;
            }
            else
            {
                this.Error = e.Error;
            }
            m_Event.Set();
        }

        public void SetAppItems(IEnumerable<AppItemDescriptor> items)
        {
#if USE_WCF_METASERVICE_CLIENT
            m_Client.SetAppItemAsync(new List<AppItemDescriptor>(items));
            m_Event.WaitOne();

            if (this.Error != null)
            {
                throw this.Error;
            }
#endif
        }

        /// <summary>
        /// Возвращает исключение, возникшее при обращении к серверу.
        /// Если исключения не произошло возвращает null.
        /// </summary>
        public Exception Error { get; private set; }

        public event EventHandler<GetAppItemsCompletedEventArgs> GetAppItemsAsyncCompleted;
        protected void OnGetUserSettingsAsyncCompleted(GetAppItemsCompletedEventArgs e)
        {
            if (this.GetAppItemsAsyncCompleted != null)
            {
                this.GetAppItemsAsyncCompleted(this, e);
            }
        }

        public IEnumerable<AppItemDescriptor> GetAppItems(List<AppItemDescriptor> cachedItems)
        {
#if USE_WCF_METASERVICE_CLIENT
            m_Client.GetAppItemsAsync(cachedItems);
#else
            var xmlStr = XmlUtility.Obj2XmlStr(cachedItems);
            byte[] buff = Encoding.Unicode.GetBytes(xmlStr);
            xmlStr = null;
            m_Client.BeginGetRequestStream(new AsyncCallback(RequestStreamObtained), buff);
#endif
            m_Event.WaitOne();

            if (this.Error != null)
            {
                throw this.Error;
            }

            return m_Res;
        }

#if USE_WCF_METASERVICE_CLIENT
#else
        private void RequestStreamObtained(IAsyncResult ar)
        {
            try
            {
                byte[] buff = (byte[])ar.AsyncState;
                var stream = m_Client.EndGetRequestStream(ar);
                stream.Write(buff, 0, buff.Length);
                stream.Close();

                m_Client.BeginGetResponse(new AsyncCallback(ResponseObtained), null);
            }
            catch (Exception exc)
            {
                this.Error = exc;
                m_Event.Set();
            }
        }

        private void ResponseObtained(IAsyncResult ar)
        {
            try
            {
                using (var response = m_Client.EndGetResponse(ar))
                {
                    var stream = response.GetResponseStream();
                    var xmlStr = string.Empty;
                    using (var sr = new StreamReader(stream))
                    {
                        xmlStr = sr.ReadToEnd();
                    }
                    stream.Close();

                    m_Res = XmlUtility.XmlStr2Obj<List<AppItemDescriptor>>(xmlStr);
                }
            }
            catch (Exception exc)
            {
                this.Error = exc;
            }
            finally
            {
                m_Event.Set();
            }
        }
#endif

        #region IDisposable Members

        public void Dispose()
        {
#if USE_WCF_METASERVICE_CLIENT
            try
            {
                m_Client.Abort();
            }
            catch
            {
                // doesnt matter
            }
#endif
        }

        #endregion
    }
}
